#ifndef STREAMPARSER_H
#define STREAMPARSER_H

#include <functional>
#include <vector>
#include <string>
#include <iterator>
#include <cstring> //std::memmove
#include "Utils.h"
#include "LogMod.h"
namespace tool {

/*!
 * @brief translate string to hex type ,e.g. "hello"->"68656C6C6F"
 * @param buffer
 * @return
*/
std::string ToHex(const std::string& buffer);

/*!
 * @brief translate hex type string to normal string, e.g. "68"->"h"
 * @param buffer
 * @return
*/
std::string FromHex(const std::string& buffer);

/*!
 * @brief crc32 check
 * @param buf 
 * @param len 
 * @param crc 
 * @return 
*/
uint32_t CheckCRC32(const char* buf, int len, uint32_t crc = 0xffffffff);


class BinaryStream {

    template<typename T>
    using IsInputIter = typename std::is_convertible<
        typename std::iterator_traits<T>::iterator_category,
        std::input_iterator_tag>;

    template<typename T>
    using IsCharContainer = typename std::is_same<typename T::value_type, char>;

    template<typename T>
    using IsBaseType = typename std::is_arithmetic<T>;
#ifdef _MSC_VER
    template<typename T>
    using IsOtherContainer = typename std::negation<std::is_same<typename T::value_type, char>>;
#else
    template<typename T>
    using IsOtherContainer = typename std::__not_<std::is_same<typename T::value_type, char>>;
#endif

public:
    BinaryStream() = default;

    explicit BinaryStream(std::string str)
        :m_buffer(std::move(str))
    {}

    template<typename T>
    typename std::enable_if_t<IsBaseType<T>::value, BinaryStream&>
        operator<<(T value)
    {
        int writePos = m_buffer.size();
        m_buffer.resize(writePos + sizeof(value));
        *reinterpret_cast<T*>(&m_buffer[writePos]) = value;
        return *this;
    }

    template<typename T>
    typename std::enable_if_t<IsCharContainer<T>::value, BinaryStream&>
        operator<<(const T& value)
    {
        Write(value.begin(), value.end());
        return *this;
    }

    template<typename T>
    typename std::enable_if_t<IsOtherContainer<T>::value, BinaryStream&>
        operator<<(const T& value)
    {
        for (const auto& v : value)
            operator<<(v);
        return *this;
    }

    void Write(const char* data, int size)
    {
        int writePos = m_buffer.size();
        m_buffer.reserve(writePos + size);
        m_buffer.insert(m_buffer.end(), data, data + size);
    }

    template<class T,
        typename = std::enable_if_t<IsInputIter<T>::value, void>>
        void Write(T first, T last)
    {
        m_buffer.insert(m_buffer.end(), first, last);
    }

    const std::string& Str() const
    {
        return m_buffer;
    }

    std::string& Str()
    {
        return m_buffer;
    }

    const char* Data() const
    {
        return m_buffer.data();
    }

    int Size() const
    {
        return m_buffer.size();
    }
private:
    std::string m_buffer;
};





class StreamParser
{
public:
    void RegisterUpdator(std::function<void(const char*, int)> functor)
    {
        m_updator = std::move(functor);
    }

    void InstallParser(std::function<int(const char*, int)> functor)
    {
        m_parser = std::move(functor);
    }

    void Update(const char* data, int size)
    {
        if (!m_parser)
            return;
        m_buffer.insert(m_buffer.end(), data, data + size);
        Parse();
    }

private:
    void Parse();

    void Clear() {
        m_buffer.clear();
    }
private:
    std::vector<char>                     m_buffer;
    std::function<void(const char*, int)> m_updator;
    std::function<int(const char*, int)>  m_parser;
};



/*!
 * \brief UpdateCommonPackage,通用粘包数据解析
 * 只要一个数据包结构满足(Head+Size+...+Tail)就可以使用这个通用的解析模板
 * \param data
 * \param size
 * \return -1 表示错误,0 表示长度不够,其他表示解析出的数据包长度
 */
#ifdef _MSC_VER
template<typename HTType, HTType Head, HTType Tail, typename SizeType,
    typename = std::enable_if_t<std::conjunction<std::is_integral<HTType>, std::is_integral<SizeType>>::value, void>>
#else
template<typename HTType, HTType Head, HTType Tail, typename SizeType,
    typename = std::enable_if_t<std::__and_<std::is_integral<HTType>, std::is_integral<SizeType>>::value, void>>
#endif
    int UpdateCommonPackage(const char* data, int size) {
    static constexpr int sc_BaseSize = sizeof(Head) + sizeof(Tail) + sizeof(SizeType);
    //首先判断包的长度，如果长度不够直接返回
    if (size < sc_BaseSize)
        return 0;
    //检查帧头，不符则直接返回错误
    HTType head = *reinterpret_cast<const HTType*>(data);
    if (head != Head) {
        LOG_D("invalid data head:0x%08X",head);
        return -1;
    }

    //读取当前包的长度
    SizeType dataLen = *reinterpret_cast<const SizeType*>(data + sizeof(head));
    //检查当前接收的长度是否不足当前包的长度
    if (size < static_cast<int>(dataLen))
        return 0;

    //检查帧尾，不符则直接返回错误
    HTType tail = *reinterpret_cast<const HTType*>(data + dataLen - sizeof(Tail));
    if (tail != Tail) {
        LOG_D("invalid data tail:0x%08X",tail);
        return -1;
    }
    else {
        return dataLen;
    }
}


}//namespace tool


#endif // STREAMPARSER_H


